package cn.dyn.funchat.netty.server;

import cn.dyn.funchat.channel.ChannelInit;
import cn.dyn.funchat.netty.server.prop.NettyProp;
import cn.dyn.funchat.utils.TraceIdUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;


/**
 * netty websocket 服务器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class NettyWebsocketStarter implements CommandLineRunner {
    /**
     * netty的yml配置
     */
    private final NettyProp nettyProp;
    /**
     * 用于处理连接
     */
    private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    /**
     * 用于处理消息
     */
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();


    @Override
    public void run(String... args) {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            // 异步io
            serverBootstrap.channel(NioServerSocketChannel.class);
            // 日志配置
            serverBootstrap.handler(new LoggingHandler(LogLevel.DEBUG));
            // 初始化channel，用于处理业务
            serverBootstrap.childHandler(new ChannelInit(nettyProp));
            Integer port = nettyProp.getWebsocket().getPort();
            // 绑定端口，异步启动
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            log.info("========== netty websocket服务启动成功，端口号：{} ==========", port);
            // 等待关闭 这里会一直阻塞，导致后面的spring boot代码无法执行，
            // 导致整个spring boot项目启动不成功
            // channelFuture.channel().closeFuture().sync();
            final String traceId = TraceIdUtil.gutTraceId();
            channelFuture.addListener((ChannelFutureListener) future -> {
                TraceIdUtil.putTraceId(traceId);
                if (future.isSuccess()) {
                    log.info("Netty websocket服务启动成功，端口号：{}", port);
                } else {
                    log.error("启动失败", future.cause());
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();
                }
            });
        } catch (Exception e) {
            log.error("启动 netty websocket 服务异常：{}", e.getMessage());
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}